import {
  computed,
  createVNode,
  defineComponent,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  render,
  provide,
  inject
} from "vue";

export const DropdownItem = defineComponent({
  props:{
    label: String,
    icon: String
  },
  setup(props){
    const {label, icon} = props;

    const hide = inject('hide')

    return ()=> <div
      class='dropdown__item'
      onClick={hide}
    >
      <i class={icon}></i>
      <span>{label}</span>
    </div>
  }
});

const DropdownComponent = defineComponent({
  props: {
    option: {type:Object}
  },
  setup(props,ctx){
    const state = reactive({
      option: props.option,
      visible: false,
      top: 0,
      left: 0
    });

    ctx.expose({
      showDropdown(option) {
        state.option = option;
        state.visible = true;
        const {left,top,height} = option.el.getBoundingClientRect();
        state.top = top + height;
        state.left = left;
      }
    });

    provide('hide', () => state.visible = false);

    const classes = computed(() => [
      'dropdown',
      {
        'dropdown--isShow': state.visible
      }
    ]);

    const styles = computed(() => ({
      top: state.top + 'px',
      left: state.left + 'px'
    }));

    const el = ref();
    const onMousedownDocument = (e)=>{
      if(!el.value.contains(e.target)){
        state.visible = false;
      }
    }

    onMounted(() => {
      document.addEventListener(
        'mousedown',
        onMousedownDocument,
        //捕获阶段执行, 因为可能下面的组件有的阻止了冒泡
        true
      )
    });

    onBeforeUnmount(()=>{
      document.removeEventListener('mousedown', onMousedownDocument)
    })

    return () => {
      return <div
        class={classes.value}
        style={styles.value}
        ref={el}
      >
        {state.option.content()}
      </div>
    };
  }
})

let componentVNode;
export function $dropdown(option) {
  if(!componentVNode){
    //step1
    const el = document.createElement('div');
    //step2
    componentVNode = createVNode(DropdownComponent, {option});
    //step3
    render(componentVNode, el); //此时componentVNode的component属性就有值了
    //使用vue 要想自己手动渲染一个虚拟节点, 就必须经过以上三步, 之所以有第一步, 是因为vue提供的render函数必须要接受一个el
    //render还能提供diff的能力
    document.body.appendChild(
      el
    );
  }
  //↑不用关心怎么关闭隐藏弹窗 因为ElDialog已经帮我们做了 只需要点击mask即可隐藏弹窗

  const {showDropdown} = componentVNode.component.exposed;
  showDropdown(option);
}

